package com.xrh.tank;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.ImageIcon;

/**
 * @author 肖荣辉
 * @function 坦克大战的主窗口
 * @date 2014-2-28
 */
public class TankClient extends Frame {
	
	private static final long serialVersionUID = 1L;
	public  static final int GAME_WIDTH=640;
	public  static final int GAME_HEIGHT=480;
	int x=50,y=50;//坦克的初始坐标
	Image offScreenImage=null;//声明个图片对象
	Tank myTank=new Tank(50, 50,true,Tank.Direction.STOP,this);//我军坦克
	List <Tank> tanks=new ArrayList<Tank>();//敌军坦克
	List<Explode> explodes=new ArrayList<Explode>();//爆炸
	List<Missile> missiles=new ArrayList<Missile>();
	Missile m=null; //该炮弹收到坦克fire()方法的影响,那如何影响到呢?
	Blood b=new Blood();
	ImageIcon bg=new ImageIcon(getClass().getResource("images/bgs.jpg"));//背景图
	Point[] point={new Point(x, y)};
	int[] xpoints={430,140,220,260,200,410,470,525,560};
	int[] ypoints={120,240,340,310,240,140,160,215,175};
	Polygon polygon=new Polygon(xpoints, ypoints, xpoints.length);
	private static Random r=new Random();//随机数产生器
	
	//重画方法,当创建窗口的时候会自动调用这个方法,Graphics是画笔,系统自动传入,默认黑色
	/**
	 * 在游戏窗口中画出坦克,子弹,墙体,爆炸
	 */
	public void paint(Graphics g) {
		g.drawImage(bg.getImage(),0,0,this);//画背景图
		/*g.drawString("发射炮弹数量:"+missiles.size(),500,50 );//统计下发射的炮弹数量
		g.drawString("爆炸数量:"+explodes.size(),400,50 );//统计下发射的炮弹数量
		g.drawString("坦克数量:"+tanks.size(),300,50 );//统计下发射的炮弹数量
		g.drawString("生命值::"+myTank.getLife(),200,50 );//统计下发射的炮弹数量
		 */		
		
		//敌人死光了,加20辆
		if(tanks.size()<=0){
			for(int i=0;i<20;i++){//添加10量敌军坦克
				tanks.add(new Tank(10+r.nextInt(GAME_WIDTH-20),10+r.nextInt(GAME_HEIGHT-20),false,Tank.Direction.D,this));
			}
		}
		
		for(int i=0;i<tanks.size();i++){//画出敌军坦克
			Tank tank=tanks.get(i);
			tank.collidesWithTanks(tanks);
			tank.collidesWithLine();//是否开到河边
			tank.draw(g);
		}
		
		for (int i = 0; i < missiles.size(); i++) {//画出数组中的炮弹
			Missile m=missiles.get(i);
			m.hitTanks(tanks);//看看这颗子弹到底命中了数组中的哪辆坦克
			m.hitTank(myTank);//让炮弹可以打中自己
			m.draw(g);
		}
		
		for(int i=0;i<explodes.size();i++){//画出数组中的爆炸
			Explode e=explodes.get(i);
			e.draw(g);
		}
		myTank.collidesWithLine();//是否开到河边
		myTank.eat(b);//坦克加血
		myTank.draw(g);//画我军坦克
		b.draw(g);//画血块
	}
	
	//重写update方法,避免在屏幕上用背景色擦除,改为在内存中擦除
	/**
	 *把游戏中的元素先画到图片中,然后再把图片画到屏幕上 
	 */
	public void update(Graphics g) {
		//为null的时候才去新建,省得每次新建浪费空间
		if(offScreenImage==null){
			//在此窗口上新建一个比窗口还要大的图片,返回,让offScreenImage指向它
			offScreenImage=this.createImage(GAME_WIDTH,GAME_HEIGHT);
		}
		Graphics gOffScreen=offScreenImage.getGraphics();//拿到此图片上的画笔
		Color c=gOffScreen.getColor();//获取默认颜色
		gOffScreen.setColor(Color.GREEN);//设置为绿色画笔
		gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);//1,2参数是相对于该图片的坐标,在图片上用绿颜色方块覆盖
		gOffScreen.setColor(c);//恢复画笔颜色
		paint(gOffScreen);//注意:使用谁的画笔就画在谁身上,调用paint方法,在图片上作画.
		g.drawImage(offScreenImage, 0, 0,null);//把图片画到窗口上,2,3参数是相对于窗口的坐标,4号参数observer表示图片在画的过程中,该参数会根据过程的变化,进行相应的操作,好像是该操作要随图片的变化而变化,在我们这里暂时没什么用
	}


	/**
	 * 本方法显示坦克主窗口
	 */
	public void launchFrame(){
		for(int i=0;i<10;i++){//添加10量敌军坦克
			tanks.add(new Tank(10+r.nextInt(GAME_WIDTH-20),10+r.nextInt(GAME_HEIGHT-20),false,Tank.Direction.D,this));
		}
		this.setLocation(250,100);//设置窗口左上角的坐标点,屏幕左上角为坐标
		this.setSize(GAME_WIDTH, GAME_HEIGHT);//设置窗口高和宽
		this.setTitle("坦克大战");
		//给游戏窗口添加监听事件
		/**
		 * 理解:
		 *        给被窗口添加监听事件可以这么理解,就是让窗口上的按钮绑定适配器上
		 *        所事先定义好的方法,它们自己回自动去绑定.当按钮触发的时候,就使用
		 *        该适配器对象调用相应的方法.
		 */
		this.addWindowListener(new WindowAdapter() {  //使窗口可以关闭,传入匿名类
			public void windowClosing(WindowEvent e) {
				System.exit(0); //jvm停止运行,内存释放,也就是结束程序,从而窗口关闭
			}
		});
		this.addKeyListener(new KeyMoniter());//给键盘添加监听事件
		this.setBackground(Color.green);//背景色设置为绿色,表示草地
		this.setResizable(false);//窗口大小不可以调整
		this.setVisible(true);  //设置窗口可见
		//调用坦克移动的线程
		new Thread(new PaintThread()).start();//窗口画完就启动线程
	}
	
	public static void main(String[] args) {
		TankClient tankClient=new TankClient();
		tankClient.launchFrame();
	}
	
	//创建内部线程类,让坦克动起来,因为该类只给坦克类服务,所以写在内部可以方便的调用坦克类的方法
	private class PaintThread implements Runnable{
		public void run() {
			while(true){
				repaint();//方便的调用外层包装类的方法
				try {
					Thread.sleep(100);//每100ms调用一次
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	//创建键盘监听适配器
	private class KeyMoniter extends KeyAdapter{
		//重写键盘按下事件
		public void keyPressed(KeyEvent e) {
			myTank.keyPressed(e); //某键被按下让坦克自己根据这个键做相应的处理
		}
		//重写键盘弹起事件
		public void keyReleased(KeyEvent e) {
			myTank.keyReleased(e);
		}
		
	}
	
}
